package demo3;

public class MyBlockingQueue {
    // 定义一个数组来存放数据 具体的容量由构造方法来决定
    private Integer[] elementData = null;
    // 定义头尾下标
    private volatile int head = 0;
    private volatile int tail = 0;
    // 定义数组中元素个数
    private volatile int size = 0;


    // 构造方法
    public MyBlockingQueue(int capacity) {
        if (capacity <= 0) {
            throw new RuntimeException("队列容量必须大于零...");
        }
        elementData = new Integer[capacity];
    }


    // 插入数据的方法
    public void put(Integer value) throws InterruptedException {
        synchronized (this) {

            // 判断队列是否已满
            while (size >= elementData.length) {
                // 阻塞队列在队列满的时候就应该阻塞等待
                // 等待
                this.wait();
            }

            // 插入数据的过程
            // 在队尾插入元素
            elementData[tail] = value;
            // 移动队尾下标
            tail++;
            // 处理队尾下标
            if (tail >= elementData.length) tail = 0;
            // 修改size值
            size++;
            // 唤醒阻塞线程
            this.notifyAll();
        }
    }


    // 获取数据的方法
    public synchronized Integer take() throws InterruptedException {
        // 判断数组是否为空
        while (size == 0) {
            this.wait();
        }

        // 出队的过程
        // 获取要出对的元素
        Integer value = elementData[head];
        // 移动对头下标
        head++;
        // 处理对头下标
        if (head >= elementData.length) head = 0;
        // 处理数组中的元素个数
        size--;
        // 唤醒阻塞等待的队列
        this.notifyAll();
        // 返回元素
        return value;
    }
}
